package asteroids.model.programs.expressions;

import asteroids.model.GameObject;
import asteroids.model.Ship;

public class ExprEntityEvaluator implements ExprEvaluator<GameObject> {

	public ExprEntityEvaluator(Ship ship) {
		this.ship = ship;
	}

	public Ship getShip() {
		return ship;
	}
	
	private final Ship ship;

	@Override
	public GameObject evaluate(And and) {
		throw new IllegalArgumentException("&& operator cannot evaluate to a GameObject at line "+and.getLine()+", column "+and.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Or or) {
		throw new IllegalArgumentException("|| operator cannot evaluate to a GameObject at line "+or.getLine()+", column "+or.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(LessThan lt) {
		throw new IllegalArgumentException("<= operator cannot evaluate to a GameObject at line "+lt.getLine()+", column "+lt.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(GreaterThan gt) {
		throw new IllegalArgumentException(">= operator cannot evaluate to a GameObject at line "+gt.getLine()+", column "+gt.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Equality eq) {
		throw new IllegalArgumentException("== operator cannot evaluate to a GameObject at line "+eq.getLine()+", column "+eq.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Add add) {
		throw new IllegalArgumentException("+ operator cannot evaluate to a GameObject at line "+add.getLine()+", column "+add.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Subtract sub) {
		throw new IllegalArgumentException("- operator cannot evaluate to a GameObject at line "+sub.getLine()+", column "+sub.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Division div) {
		throw new IllegalArgumentException("/ operator cannot evaluate to a GameObject at line "+div.getLine()+", column "+div.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Multiply mul) {
		throw new IllegalArgumentException("* operator cannot evaluate to a GameObject at line "+mul.getLine()+", column "+mul.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(DoubleLiteral d) {
		throw new IllegalArgumentException("DoubleLiteral cannot evaluate to a GameObject at line "+d.getLine()+", column "+d.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(BooleanLiteral b) {
		throw new IllegalArgumentException("BooleanLiteral cannot evaluate to a GameObject at line "+b.getLine()+", column "+b.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Not not) {
		throw new IllegalArgumentException("! operator cannot evaluate to a GameObject at line "+not.getLine()+", column "+not.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Sqrt sqrt) {
		throw new IllegalArgumentException("Math.sqrt() cannot evaluate to a GameObject at line "+sqrt.getLine()+", column "+sqrt.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Sin sin) {
		throw new IllegalArgumentException("Math.sin() cannot evaluate to a GameObject at line "+sin.getLine()+", column "+sin.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Cos cos) {
		throw new IllegalArgumentException("Math.cos() cannot evaluate to a GameObject at line "+cos.getLine()+", column "+cos.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(GetDirection getDir) {
		throw new IllegalArgumentException("GetDirection cannot evaluate to a GameObject at line "+getDir.getLine()+", column "+getDir.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Self self) {
		return getShip();
	}

	@Override
	public GameObject evaluate(GetX getX) {
		throw new IllegalArgumentException("GetX cannot evaluate to a GameObject at line "+getX.getLine()+", column "+getX.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(GetY getY) {
		throw new IllegalArgumentException("GetY cannot evaluate to a GameObject at line "+getY.getLine()+", column "+getY.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(GetVX getVX) {
		throw new IllegalArgumentException("GetVX cannot evaluate to a GameObject at line "+getVX.getLine()+", column "+getVX.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(GetVY getVY) {
		throw new IllegalArgumentException("GetVY cannot evaluate to a GameObject at line "+getVY.getLine()+", column "+getVY.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(GetRadius getRadius) {
		throw new IllegalArgumentException("GetRadius cannot evaluate to a GameObject at line "+getRadius.getLine()+", column "+getRadius.getColumn()+"!");
	}

	@Override
	public GameObject evaluate(Variable var) {
		GameObject go;
		try {
			go = getShip().getProgram().getAssignment(var.getName()).accept(this);
		}
		catch(IllegalArgumentException exc) {
			throw new IllegalArgumentException("Variable cannot evaluate to a GameObject at line "+var.getLine()+", column "+var.getColumn()+"!", exc);
		}
		catch(NullPointerException exc) {
			throw new IllegalArgumentException("Encountered a null reference while trying to evaluate the variable at line "+var.getLine()+", column "+var.getColumn()+"!", exc);
		}
		return go;
	}

	@Override
	public GameObject evaluate(EntityLiteral el) {
		return el.getGameObject();
	}

	@Override
	public GameObject evaluate(Null null1) {
		return null;
	}

}
